package xin.tomdonkey.chat.udp.protocal;

import xin.tomdonkey.chat.udp.SPException;
import xin.tomdonkey.chat.udp.util.ByteUtils;

import java.util.Arrays;
import java.util.UUID;


/**
 *<table>
 *  <tr>
 *    <td ALIGN=CENTER>type</td>
 *    <td ALIGN=CENTER>id</td>
 *    <td ALIGN=CENTER>loadLength</td>
 *    <td ALIGN=CENTER>load</td>
 *  </tr>
 *  <tr>
 *    <td ALIGN=CENTER>1byte</td>
 *    <td ALIGN=CENTER>36byte</td>
 *    <td ALIGN=CENTER>2byte</td>
 *    <td ALIGN=CENTER>{@link SP#SP_MAX_LOAD_SIZE}byte</td>
 *  </tr>
 * </table>
 * @author guolinyuan
 */
public class SP
{
    public static final int UDP_MAX_SIZE = 65507;
    public static final int SP_TYPE_SIZE = Byte.SIZE / 8 ;
    public static final int SP_ID_SIZE = UUID.randomUUID().toString().getBytes().length;
    public static final int SP_LOAD_LENGTH_SIZE =  Short.SIZE / 8 ;
    public static final int SP_HEAD_SIZE = SP_TYPE_SIZE + SP_ID_SIZE + SP_LOAD_LENGTH_SIZE;
    public static final int SP_MAX_LOAD_SIZE = UDP_MAX_SIZE - SP_HEAD_SIZE;


    /**
     * 收到回复响应
     */
    public static final short ACK = 0;

    /**
     * utf-8编码普通文本数据
     */
    public static final short TEXT = 1;


    /**
     * 数据类型1字节
     * 请取值在0-255之间
     * 实际上是一个 unsigned  byte,将转为一个byte数据放在数组中
     */
    private short type;

    private String id;

    /**
     * 数据载荷长度 0-{@link SP#SP_MAX_LOAD_SIZE}字节
     * 际上是一个 unsigned  short,将转为2byte数据放在数组中
     */
    private int loadLength;

    /**
     * 数据载荷 最大{@link SP#SP_MAX_LOAD_SIZE}字节
     */
    private byte[] load;

    public SP()
    {
    }

    public static SP text(String data)
    {
        byte[] dataBates = data.getBytes();
        if (dataBates.length <= UDP_MAX_SIZE)
            return new SP((byte) TEXT, dataBates);
        else
            throw new SPException("数据过长!请分段发送");
    }

    public static SP ack(String id)
    {
        return new SP((byte) ACK, null, id);
    }

    private SP(byte type, byte[] load)
    {
        this(type, load, UUID.randomUUID().toString());
    }

    private SP(short type, byte[] load, String id)
    {
        if (load != null )
        {
            if (load.length > SP_MAX_LOAD_SIZE)
                throw new SPException("单包数据过大!构造失败!");
            this.load = load;
            this.loadLength = load.length;
        }
        else
            this.loadLength = 0;
        this.type = type;
        this.id = id;
    }

    public static SP parseSP(byte[] data)
    {
        if (data == null || data.length < SP_HEAD_SIZE)
            throw new SPException("数据为null或不符合规范");
        SP sp = new SP();
        sp.type = (short) Byte.toUnsignedInt(data[0]);
        sp.id = new String(data, SP_TYPE_SIZE, SP_ID_SIZE);
        sp.loadLength = ByteUtils.byte2ToUnsignedShort(Arrays.copyOfRange(data, SP_TYPE_SIZE + SP_ID_SIZE, SP_TYPE_SIZE + SP_ID_SIZE + SP_LOAD_LENGTH_SIZE),0);
        sp.load = Arrays.copyOfRange(data, SP_HEAD_SIZE, SP_HEAD_SIZE + sp.loadLength);
        return sp;
    }

    public byte[] toBytes()
    {
        int resultLength = SP_HEAD_SIZE;
        if (load != null)
            resultLength += load.length;
        byte[] result = new byte[resultLength];

        result[0] = (byte) this.type;

        byte[] idBytes = this.id.getBytes();
        System.arraycopy(idBytes, 0, result, SP_TYPE_SIZE, idBytes.length);

        byte[] loadLengthBytes = ByteUtils.unsignedShortToByte2(this.loadLength);
        System.arraycopy(loadLengthBytes, 0, result, SP_TYPE_SIZE + SP_ID_SIZE, loadLengthBytes.length);

        if (load != null)
            System.arraycopy(load, 0, result, SP_HEAD_SIZE, load.length);
        return result;
    }

    @Override
    public String toString()
    {
        return "SP{" +
                "type=" + type +
                ", id='" + id + '\'' +
                ", loadLength=" + loadLength +
                ", load=" + Arrays.toString(load) +
                '}';
    }

    public short getType()
    {
        return type;
    }

    public String getId()
    {
        return id;
    }

    public byte[] getLoad()
    {
        return load;
    }
}
